using System;
using ch.ethz.ssh2.crypto.digest;
using ch.ethz.ssh2.log;
using ch.ethz.ssh2.util;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Math;
namespace ch.ethz.ssh2.crypto.dh
{

    /// <summary> DhExchange.
    /// 
    /// </summary>
    /// <author>  Christian Plattner
    /// </author>
    /// <version>  2.50, 03/15/10
    /// </version>
    public class DhExchange
    {
        /// <returns> Returns the e.
        /// </returns>
        /// <throws>  IllegalStateException </throws>
        virtual public BigInteger E
        {
            get
            {
                if (e == null)
                    throw new System.SystemException("DhDsaExchange not initialized!");

                return e;
            }

        }
        /// <returns> Returns the shared secret k.
        /// </returns>
        /// <throws>  IllegalStateException </throws>
        virtual public BigInteger K
        {
            get
            {
                if (k == null)
                    throw new System.SystemException("Shared secret not yet known, need f first!");

                return k;
            }

        }
        /// <param name="f">
        /// </param>
        virtual public BigInteger F
        {
            set
            {
                if (e == null)
                    throw new System.SystemException("DhDsaExchange not initialized!");

                BigInteger zero = BigInteger.ValueOf(0);

                if (zero.CompareTo((System.Object)value) >= 0 || p.CompareTo((System.Object)value) <= 0)
                    throw new System.ArgumentException("Invalid f specified!");

                this.f = value;
                
                this.k = f.ModPow(x, p);
            }

        }
        //UPGRADE_NOTE: Final was removed from the declaration of 'log '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
        //UPGRADE_NOTE: The initialization of  'log' was moved to static method 'ch.ethz.ssh2.crypto.dh.DhExchange'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'"
        private static readonly Logger log;

        /* Given by the standard */

        internal static BigInteger p1;
        internal static BigInteger p14;
        internal static BigInteger g;

        internal BigInteger p;

        /* Client public and private */

        internal BigInteger e;

        internal BigInteger x;

        /* Server public */

        internal BigInteger f;

        /* Shared secret */

        internal BigInteger k;

        public DhExchange()
        {
        }

        public virtual void init(int group, SecureRandom rnd)
        {
            k = null;

            if (group == 1)
                p = p1;
            else if (group == 14)
                p = p14;
            else
                throw new System.ArgumentException("Unknown DH group " + group);

            x = new BigInteger(p.BitLength - 1, rnd);

            e = g.ModPow(x, p);
        }

        public virtual byte[] calculateH(byte[] clientversion, byte[] serverversion, byte[] clientKexPayload, byte[] serverKexPayload, byte[] hostKey)
        {
            HashForSSH2Types hash = new HashForSSH2Types("SHA1");

            if (log.Enabled)
            {
                log.log(90, "Client: '" + StringEncoder.GetString(clientversion) + "'");
                log.log(90, "Server: '" + StringEncoder.GetString(serverversion) + "'");
            }

            hash.updateByteString(clientversion);
            hash.updateByteString(serverversion);
            hash.updateByteString(clientKexPayload);
            hash.updateByteString(serverKexPayload);
            hash.updateByteString(hostKey);
            hash.updateBigInt(e);
            hash.updateBigInt(f);
            hash.updateBigInt(k);

            return hash.getDigest();
        }


        static DhExchange()
        {
            log = Logger.getLogger(typeof(DhExchange));
            {
                const string p1_string = "17976931348623159077083915679378745319786029604875" + "60117064444236841971802161585193689478337958649255415021805654859805036464" + "40548199239100050792877003355816639229553136239076508735759914822574862575" + "00742530207744771258955095793777842444242661733472762929938766870920560605" + "0270810842907692932019128194467627007";

                const string p14_string = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129" + "024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0" + "A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB" + "6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A" + "163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208" + "552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36C" + "E3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF69558171" + "83995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF";

                p1 = new BigInteger(p1_string);
                p14 = new BigInteger(p14_string, 16);
                g = new BigInteger("2");
            }
        }
    }
}